Managing db schema changes without downtime
Discourseのエンジニアによる2018年の記事
https://samsaffron.com/archive/2018/03/22/managing-db-schema-changes-without-downtime
互換性のないデータベーススキーマを作成してしまうことの問題
古いバージョンのコードを実行している古いアプリケーションインスタンスがすべて壊れてしまう危険性がある
ActiveRecord では、状況は特に悲惨
本番環境ではデータベーススキーマはキャッシュされており、カラムのドロップや名前の変更を非常に迅速に行うスキーマの変更は、影響を受けるモデルへのすべてのクエリを破壊し、無効なスキーマ例外を発生させる危険性がある
Discourseのアプローチ
マイグレーションに関する情報を追跡できるようにしている
ActiveRecord には schema_migrations というテーブルがあり、実行されたmigrationsの記録があるが情報が少ない
ActiveRecord::Migrationにprependして、欲しい情報を追加している
マイグレーションがいつ実行されたか
移行が実行されるまでにかかった時間
移行が実行されたときに実行されていたRailsのバージョン
モンキーパッチ
https://github.com/discourse/discourse/blob/6a3c8fe69c16ad7360046f145db6689c18e91005/lib/freedom_patches/schema_migration_details.rb
危険なマイグレーションの遅延実行
マイグレーションの情報が残っているので、新しいコードが危険なスキーマ変更の後の状態をハンドリングできることを保証してからmigrationするよう遅延(defer)できる
実際にはdb/seedでdrop columnする
この遅延ドロップは、参照している特定のマイグレーションが実行されてから少なくとも30分後(次のマイグレーションサイクルで)に実行される
カラムの名前を変更したい場合は、新しいカラムを作成し、値を新しいカラムに複製し、トリガーを使用して古いカラムを読み取り専用にマークし、古いカラムのドロップを延期します
テーブルを削除したり名前を変更したい場合は、同様のパターンに従う
ColumnDropperのような便利moduleがある
危険なマイグレーションの実行禁止
PG gemにパッチをあて、dropやrenameのような危険な変更を行おうとすると例外が起きるようにした
https://github.com/discourse/discourse/blob/6a3c8fe69c16ad7360046f145db6689c18e91005/lib/migration/safe_migrate.rb
上述のプラクティスを強制している
Alternatives
Discourseと似たことをやっているgemたち
https://github.com/ankane/strong_migrations
マイグレーションのルールを強制するgem
PostgreSQL, MySQL, MariaDB対応
ActiveRecord migratorにパッチを当てているのでSQL直実行には対処できない
2020-10でもメンテナンスされている
https://github.com/LendingHome/zero_downtime_migrations
strong_migrationsと似ている
PostgreSQL対応
2018でメンテナンスが止まっている
https://github.com/instructure/outrigger
Rails migrationにタグ付けする
migrationを実行するのがデプロイ前なのか後なのかをコントロールできるようになる
https://github.com/procore/handcuffs
outtriggerに似ている
Railsへの提案
結局すべてRailsに属するものなのでRails本体で危険なマイグレーションの禁止、安全なゼロダウンタイムデプロイのサポートをしてほしい
案
マイグレーションスクリプトにafter_deploy!を記述できる
db:migrate:pre, db:migrate:postコマンドにより、after_deploy!付き(もしくはつかないもの)のスクリプトだけ実行できる
db:migrateはそのまま
Conclusion
安全なゼロダウンタイムデプロイを始めたいなら以下をおすすめする
マイグレーションをデプロイ前または後に実行できるようビルドプロセスを変える
outtrigger, handcuffsを使うのも良い
マイグレーションに強制力をもたせる
strong_migration
関連 100 Percent Online Deployments: Blue-Green Deployment